use std::cmp::Ordering;

use async_trait::async_trait;
use rust_mcp_sdk::mcp_server::ServerHandler;
use rust_mcp_sdk::schema::{
    schema_utils::CallToolError, CallToolRequest, CallToolResult, InitializeRequest,
    InitializeResult, ListToolsRequest, ListToolsResult, RpcError,
};
use rust_mcp_sdk::McpServer;

use crate::cli::CommandArguments;
use crate::config::Config;
use crate::error::{ServiceError, ServiceResult};
use crate::tms_client::TmsClient;
use crate::tools::*;

pub struct TmsServerHandler {
    tms_client: TmsClient,
    config: Config,
}

impl TmsServerHandler {
    pub async fn new(args: &CommandArguments) -> ServiceResult<Self> {
        // Load or generate configuration
        if let Some(config_path) = &args.generate_config {
            let config = Config::default();
            config.save_to_file(config_path)?;
            println!("Generated default configuration file: {}", config_path);
            std::process::exit(0);
        }
        
        let mut config = if let Some(config_path) = &args.config {
            Config::load_from_file(config_path)?
        } else {
            Config::from_env()
        };
        
        // Override config with command line arguments
        if args.tms_server != "http://localhost:50051" {
            config.tms.server_url = args.tms_server.clone();
        }
        config.tms.connection_timeout_ms = args.connection_timeout_ms;
        config.tms.request_timeout_ms = args.request_timeout_ms;
        config.tms.max_retries = args.max_retries;
        
        // Create TMS client with retry logic
        let tms_client = create_tms_client_with_retry(&config.tms).await?;
        
        Ok(Self { tms_client, config })
    }

    pub fn startup_message(&self) -> String {
        format!(
            "TMS MCP Server v{} started successfully.\nConnected to TMS server at: {}\nAvailable tools: {}",
            self.config.server.version,
            self.config.tms.server_url,
            TmsTools::tools().len()
        )
    }
}

#[async_trait]
impl ServerHandler for TmsServerHandler {
    async fn on_server_started(&self, runtime: &dyn McpServer) {
        let _ = runtime.stderr_message(self.startup_message()).await;
    }

    async fn on_initialized(&self, _: &dyn McpServer) {}

    async fn handle_list_tools_request(
        &self,
        _: ListToolsRequest,
        _: &dyn McpServer,
    ) -> std::result::Result<ListToolsResult, RpcError> {
        Ok(ListToolsResult {
            tools: TmsTools::tools(),
            meta: None,
            next_cursor: None,
        })
    }

    async fn handle_initialize_request(
        &self,
        initialize_request: InitializeRequest,
        runtime: &dyn McpServer,
    ) -> std::result::Result<InitializeResult, RpcError> {
        runtime
            .set_client_details(initialize_request.params.clone())
            .await
            .map_err(|err| RpcError::internal_error().with_message(format!("{err}")))?;

        let mut server_info = runtime.server_info().to_owned();
        // Provide compatibility for clients using older MCP protocol versions.
        if server_info
            .protocol_version
            .cmp(&initialize_request.params.protocol_version)
            == Ordering::Greater
        {
            server_info.protocol_version = initialize_request.params.protocol_version;
        }
        Ok(server_info)
    }

    async fn handle_call_tool_request(
        &self,
        request: CallToolRequest,
        _: &dyn McpServer,
    ) -> std::result::Result<CallToolResult, CallToolError> {
        let tool_params: TmsTools =
            TmsTools::try_from(request.params).map_err(CallToolError::new)?;

        match tool_params {
            // Vehicle Management
            TmsTools::ListVehiclesTool(params) => {
                ListVehiclesTool::run_tool(params, &mut self.tms_client.clone()).await
            }
            TmsTools::CreateVehicleTool(params) => {
                CreateVehicleTool::run_tool(params, &mut self.tms_client.clone()).await
            }
            TmsTools::GetVehicleTool(params) => {
                GetVehicleTool::run_tool(params, &mut self.tms_client.clone()).await
            }
            TmsTools::UpdateVehicleStatusTool(params) => {
                UpdateVehicleStatusTool::run_tool(params, &mut self.tms_client.clone()).await
            }
            
            // Order Management
            TmsTools::ListOrdersTool(params) => {
                ListOrdersTool::run_tool(params, &mut self.tms_client.clone()).await
            }
            TmsTools::CreateOrderTool(params) => {
                CreateOrderTool::run_tool(params, &mut self.tms_client.clone()).await
            }
            TmsTools::GetOrderTool(params) => {
                GetOrderTool::run_tool(params, &mut self.tms_client.clone()).await
            }
            TmsTools::UpdateOrderStatusTool(params) => {
                UpdateOrderStatusTool::run_tool(params, &mut self.tms_client.clone()).await
            }
            
            // Transport Planning
            TmsTools::CreateTransportPlanTool(params) => {
                CreateTransportPlanTool::run_tool(params, &mut self.tms_client.clone()).await
            }
            TmsTools::ListTransportPlansTool(params) => {
                ListTransportPlansTool::run_tool(params, &mut self.tms_client.clone()).await
            }
            TmsTools::GetTransportPlanTool(params) => {
                GetTransportPlanTool::run_tool(params, &mut self.tms_client.clone()).await
            }
            TmsTools::OptimizeRouteTool(params) => {
                OptimizeRouteTool::run_tool(params, &mut self.tms_client.clone()).await
            }
            
            // Location Services
            TmsTools::UpdateVehicleLocationTool(params) => {
                UpdateVehicleLocationTool::run_tool(params, &mut self.tms_client.clone()).await
            }
            TmsTools::GetVehicleLocationTool(params) => {
                GetVehicleLocationTool::run_tool(params, &mut self.tms_client.clone()).await
            }
            
            // System Monitoring
            TmsTools::GetSystemStatsTool(params) => {
                GetSystemStatsTool::run_tool(params, &mut self.tms_client.clone()).await
            }
            TmsTools::HealthCheckTool(params) => {
                HealthCheckTool::run_tool(params, &mut self.tms_client.clone()).await
            }
        }
    }
}

async fn create_tms_client_with_retry(config: &crate::config::TmsConfig) -> ServiceResult<TmsClient> {
    let mut attempts = 0;
    let max_attempts = config.max_retries + 1;
    
    while attempts < max_attempts {
        match TmsClient::new(&config.server_url).await {
            Ok(client) => {
                tracing::info!("Successfully connected to TMS server");
                return Ok(client);
            }
            Err(e) => {
                attempts += 1;
                if attempts >= max_attempts {
                    tracing::error!("Failed to connect to TMS server after {} attempts: {}", max_attempts, e);
                    return Err(ServiceError::TmsConnection(e.to_string()));
                }
                tracing::warn!("Failed to connect to TMS server (attempt {}/{}): {}", attempts, max_attempts, e);
                tokio::time::sleep(std::time::Duration::from_millis(1000 * attempts as u64)).await;
            }
        }
    }
    
    unreachable!()
}